#include "protocols/ArpProtocal.h"
#include "utilities/ReadablePacket.h"
#include "protocols/ProtocalCode.h"
#include "protocols/ProtocalPool.h"
#include "protocols/ShowableItem.h"
#include "utilities/utilities.h"

REGISTER_PROTOCOL(ArpProtocal)

NetAddress ArpHeader::getSrcHwAdr() const
{
	return NetAddress(ADDR_MAC,  (const u_char *)((mData + sizeof(HeaderFormat))));
}

NetAddress ArpHeader::getSrcIPAdr() const
{

	if (4 == getIPAdrLength())
	{
		return NetAddress(ADDR_IPV4, (const u_char *)((mData + sizeof(HeaderFormat)) + getHwAdrLength()));
	}
	return NetAddress(ADDR_IPV6, (const u_char *)((mData + sizeof(HeaderFormat)) + getHwAdrLength()));
}

NetAddress ArpHeader::getDesHwAdr() const
{
	return NetAddress(ADDR_MAC,(const u_char *)((mData + sizeof(HeaderFormat)) + getHwAdrLength() + getIPAdrLength()));
}

NetAddress ArpHeader::getDesIPAdr() const
{
	if (4 == getIPAdrLength())
	{
		return NetAddress(ADDR_IPV4, (const u_char *)((mData + sizeof(HeaderFormat)) + 2 * getHwAdrLength() + getIPAdrLength()));
	}
	return NetAddress(ADDR_IPV6, (const u_char *)((mData + sizeof(HeaderFormat)) + 2 * getHwAdrLength() + getIPAdrLength()));
}

QString  ArpHeader::getMesType() const
{
	switch( ntohs(((HeaderFormat *)(mData))->_mMesType))
	{
	case 1:
		return QString("ARP request(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	case 2:
		return QString("ARP respond(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	case 3:
		return QString("RARP request(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	case 4:
		return QString("PARP respond(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	case 8:
		return QString("Inverse ARP request(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	case 9:
		return QString("Inverse ARP respond(%1)").arg(toHexString((const u_char *)&((HeaderFormat *)mData)->_mMesType, 2));
	default:
		return QString("unkown");
	}
}

QString ArpHeader::getHwType() const
{
	QString type;
	switch(ntohs(((HeaderFormat*)mData)->_mHwType))
	{
	case 1:
		type = QString("Ethernet");
		break;
	case 7:
		type = QString("ARCnet");
		break;
	}
	return QString("%1 : (%2)").arg(type).arg(toHexString((const u_char *)&((HeaderFormat*)mData)->_mHwType, 2));
}

void ArpHeader::toShowableItems(ShowableItem* root) const
{
	HeaderFormat* header = (HeaderFormat*)mData;
	int pos = mPos;
	ShowableItem* tmp;

	ShowableItem* proto = createProtocalItem("ARP - Address Resolution Protocol",pos,getHeaderLength());
	root->pushChild(proto);

	tmp = createItem("HardWare Type :",getHwType(), pos, 2);
	proto->pushChild(tmp);

	tmp = createItem("Protocol Type :", getProtoInfo(), pos, 2);
	proto->pushChild(tmp);

	tmp = createItem("HardWare Addr Length :", getHwAdrLength(), pos, 1);
	proto->pushChild(tmp);

	tmp = createItem("Protocol Addr Length :", getIPAdrLength(), pos, 1);
	proto->pushChild(tmp);

	int num = ntohs(header->_mMesType);
	tmp = createItem("Operation :", getMesType(), pos, 2);
	proto->pushChild(tmp);

	tmp = createItem("Sender HardWare Addr :", getSrcHwAdr().toString(), pos, getHwAdrLength());
	proto->pushChild(tmp);

	tmp = createItem("Sender Internet Addr :", getSrcIPAdr().toString(), pos, getIPAdrLength());
	proto->pushChild(tmp);

	tmp = createItem("Target HardWare Addr :", getDesHwAdr().toString(), pos, getHwAdrLength());
	proto->pushChild(tmp); 

	tmp = createItem("Target Internet Addr :", getDesIPAdr().toString(), pos, getHwAdrLength());
	proto->pushChild(tmp);
}

ArpProtocal::ArpProtocal() : Protocol(ARP,QString("ARP"))
{
}

PacketHeader*
ArpProtocal::analyzeProc(ReadablePacket* packet,int low,int high,Protocol*& tip)
{
	ArpHeader* header = new ArpHeader(ArpProtocal_register.m_Instance,packet->getData(),low,high - low + 1);

	tip = NULL;

	return header;
}

QString ArpHeader::getProtoInfo() const
{
	int num = getProtoType();
	if (2048 == getProtoType())
	{
		return QString("IP(%1)").arg(toHexString((const u_char *)&(((HeaderFormat *)mData)->_mProType), 2));
	}
	else
	{
		return QString("unkown(%1)").arg(toHexString((const u_char *)&(((HeaderFormat *)mData)->_mProType), 2));
	}
}